import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import socket
import threading
import time

class SocketServerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Socket服务器端")
        self.root.geometry("700x700")
        
        # 服务器状态
        self.server_running = False
        self.server_socket = None
        self.client_conn = None
        self.client_address = None
        self.gui_destroyed = False  # 标记GUI是否已销毁
        
        # 创建界面
        self.create_widgets()
        
        # 绑定窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
    def create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding=10)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 标题
        title_label = ttk.Label(main_frame, text="Socket服务器端", font=("Arial", 16, "bold"))
        title_label.pack(pady=10)
        
        # 服务器配置框架
        config_frame = ttk.LabelFrame(main_frame, text="服务器配置", padding=10)
        config_frame.pack(fill=tk.X, pady=10)
        
        ttk.Label(config_frame, text="主机名:").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.host_entry = ttk.Entry(config_frame, width=20)
        self.host_entry.insert(0, "localhost")
        self.host_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.W)
        
        ttk.Label(config_frame, text="端口号:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.port_entry = ttk.Entry(config_frame, width=10)
        self.port_entry.insert(0, "12345")
        self.port_entry.grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)
        
        # 按钮框架
        button_frame = ttk.Frame(config_frame)
        button_frame.grid(row=2, column=0, columnspan=2, pady=10)
        
        self.start_button = ttk.Button(button_frame, text="启动服务", command=self.start_server)
        self.start_button.pack(side=tk.LEFT, padx=5)
        
        self.stop_button = ttk.Button(button_frame, text="停止服务", command=self.stop_server, state=tk.DISABLED)
        self.stop_button.pack(side=tk.LEFT, padx=5)
        
        # 状态显示
        status_frame = ttk.LabelFrame(main_frame, text="服务器状态", padding=10)
        status_frame.pack(fill=tk.X, pady=10)
        
        self.status_label = ttk.Label(status_frame, text="服务器未启动", foreground="red")
        self.status_label.pack(anchor=tk.W)
        
        self.connection_label = ttk.Label(status_frame, text="客户端连接: 无")
        self.connection_label.pack(anchor=tk.W, pady=5)
        
        # 新增：服务器发送消息框架
        send_frame = ttk.LabelFrame(main_frame, text="发送消息到客户端", padding=10)
        send_frame.pack(fill=tk.X, pady=10)
        
        # 输入框和发送按钮在同一行
        input_frame = ttk.Frame(send_frame)
        input_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(input_frame, text="消息:").pack(side=tk.LEFT, padx=(0, 5))
        self.server_msg_entry = ttk.Entry(input_frame, font=("Arial", 11))
        self.server_msg_entry.insert(0, "Hello, Client!")
        self.server_msg_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
        self.server_msg_entry.bind("<Return>", lambda event: self.send_to_client())
        
        self.send_to_client_button = ttk.Button(input_frame, text="发送", command=self.send_to_client, 
                                              state=tk.DISABLED, width=8)
        self.send_to_client_button.pack(side=tk.RIGHT)
        
        # 消息日志
        log_frame = ttk.LabelFrame(main_frame, text="消息日志", padding=10)
        log_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        
        self.log_text = scrolledtext.ScrolledText(log_frame, height=15, state=tk.DISABLED)
        self.log_text.pack(fill=tk.BOTH, expand=True)
        
        # 客户端消息显示
        client_frame = ttk.LabelFrame(main_frame, text="接收到的客户端消息", padding=10)
        client_frame.pack(fill=tk.X, pady=10)
        
        self.client_msg_label = ttk.Label(client_frame, text="暂无消息", background="white", relief=tk.SUNKEN)
        self.client_msg_label.pack(fill=tk.X, padx=5, pady=5)
        
    def log_message(self, message):
        """在日志中添加消息"""
        if self.gui_destroyed:  # 检查GUI是否已销毁
            return
            
        self.log_text.config(state=tk.NORMAL)
        timestamp = time.strftime("%H:%M:%S")
        self.log_text.insert(tk.END, f"[{timestamp}] {message}\n")
        self.log_text.see(tk.END)
        self.log_text.config(state=tk.DISABLED)
        
    def send_to_client(self):
        """发送消息到客户端"""
        if self.gui_destroyed:  # 检查GUI是否已销毁
            return
            
        if not self.client_conn:
            messagebox.showerror("错误", "没有客户端连接")
            return
            
        message = self.server_msg_entry.get().strip()
        if not message:
            messagebox.showwarning("警告", "消息不能为空")
            return
            
        try:
            self.client_conn.send(message.encode('utf-8'))
            self.log_message(f"发送消息到客户端: {message}")
            self.server_msg_entry.delete(0, tk.END)
        except Exception as e:
            messagebox.showerror("错误", f"发送消息失败: {str(e)}")
            self.log_message(f"发送消息失败: {str(e)}")
        
    def start_server(self):
        """启动服务器"""
        if self.gui_destroyed:  # 检查GUI是否已销毁
            return
            
        try:
            host = self.host_entry.get().strip()
            port = int(self.port_entry.get().strip())
            
            if not host:
                messagebox.showerror("错误", "请输入有效的主机名")
                return
                
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.server_socket.bind((host, port))
            self.server_socket.listen(5)
            
            self.server_running = True
            self.start_button.config(state=tk.DISABLED)
            self.stop_button.config(state=tk.NORMAL)
            self.host_entry.config(state=tk.DISABLED)
            self.port_entry.config(state=tk.DISABLED)
            
            self.status_label.config(text=f"服务器运行中 - {host}:{port}", foreground="green")
            self.log_message(f"服务器启动成功，监听 {host}:{port}")
            
            accept_thread = threading.Thread(target=self.accept_connections, daemon=True)
            accept_thread.start()
            
        except ValueError:
            messagebox.showerror("错误", "请输入有效的端口号")
        except Exception as e:
            messagebox.showerror("错误", f"启动服务器失败: {str(e)}")
            
    def stop_server(self):
        """停止服务器"""
        if self.gui_destroyed:  # 检查GUI是否已销毁
            return
            
        self.server_running = False
        
        if self.client_conn:
            try:
                self.client_conn.close()
            except:
                pass
                
        if self.server_socket:
            try:
                self.server_socket.close()
            except:
                pass
                
        # 只在GUI组件存在时才更新它们
        if hasattr(self, 'start_button'):
            self.start_button.config(state=tk.NORMAL)
        if hasattr(self, 'stop_button'):
            self.stop_button.config(state=tk.DISABLED)
        if hasattr(self, 'send_to_client_button'):
            self.send_to_client_button.config(state=tk.DISABLED)
        if hasattr(self, 'host_entry'):
            self.host_entry.config(state=tk.NORMAL)
        if hasattr(self, 'port_entry'):
            self.port_entry.config(state=tk.NORMAL)
        if hasattr(self, 'status_label'):
            self.status_label.config(text="服务器已停止", foreground="red")
        if hasattr(self, 'connection_label'):
            self.connection_label.config(text="客户端连接: 无")
            
        self.log_message("服务器已停止")
        
    def accept_connections(self):
        """接受客户端连接"""
        while self.server_running:
            try:
                self.log_message("等待客户端连接...")
                self.client_conn, self.client_address = self.server_socket.accept()
                
                self.root.after(0, self.update_connection_status)
                self.log_message(f"客户端连接来自: {self.client_address}")
                self.root.after(0, lambda: self.send_to_client_button.config(state=tk.NORMAL))
                
                receive_thread = threading.Thread(target=self.receive_messages, daemon=True)
                receive_thread.start()
                
            except OSError:
                break
            except Exception as e:
                self.log_message(f"接受连接时出错: {str(e)}")
                break
                
    def update_connection_status(self):
        """更新连接状态显示"""
        if self.gui_destroyed or not hasattr(self, 'connection_label'):
            return
            
        if self.client_conn:
            self.connection_label.config(text=f"客户端连接: {self.client_address[0]}:{self.client_address[1]}")
            
    def receive_messages(self):
        """接收客户端消息"""
        while self.server_running and self.client_conn:
            try:
                message = self.client_conn.recv(1024).decode('utf-8')
                if not message:
                    break
                    
                self.root.after(0, lambda: self.display_client_message(message))
                self.root.after(0, lambda: self.log_message(f"收到客户端消息: {message}"))
                
            except ConnectionResetError:
                self.root.after(0, lambda: self.log_message("客户端连接已断开"))
                break
            except Exception as e:
                self.root.after(0, lambda: self.log_message(f"接收消息时出错: {str(e)}"))
                break
                
        if self.client_conn:
            try:
                self.client_conn.close()
            except:
                pass
            self.client_conn = None
            self.client_address = None
            
        if not self.gui_destroyed:
            self.root.after(0, lambda: self.connection_label.config(text="客户端连接: 无"))
            self.root.after(0, lambda: self.client_msg_label.config(text="暂无消息"))
            self.root.after(0, lambda: self.send_to_client_button.config(state=tk.DISABLED))
        
    def display_client_message(self, message):
        """显示客户端消息"""
        if self.gui_destroyed or not hasattr(self, 'client_msg_label'):
            return
        self.client_msg_label.config(text=message)
    
    def on_closing(self):
        """窗口关闭事件处理"""
        self.gui_destroyed = True  # 标记GUI即将销毁
        self.stop_server()  # 先停止服务器
        self.root.destroy()  # 再销毁窗口
        
    def __del__(self):
        """清理资源 - 只处理非GUI资源"""
        # 避免在析构函数中操作GUI组件
        if self.client_conn:
            try:
                self.client_conn.close()
            except:
                pass
                
        if self.server_socket:
            try:
                self.server_socket.close()
            except:
                pass

if __name__ == "__main__":
    root = tk.Tk()
    app = SocketServerApp(root)
    root.mainloop()
